%{
# include "parser.h"

static ArrayList *result;
extern FILE *studentsin;
%}

%union {
	char *string;
	float virgula;
	int number;
	LinkedList *list;
	Student *student;
	StudentType tipo;
}

%token <string> STRING
%token <digits> DIGITS
%token <virgula> FLOAT
%token <number> NUMBER

%token LABEL_NAME 
%token OPEN CLOSE EQUAL STOP
%token LABEL_YEAR LABEL_NORMAL LABEL_EXTRA LABEL_PRO LABEL_CHOICES LABEL_WANTED
%token LABEL_MEDIA LABEL_TIPO

%start Document

%type <list> StudentChoices
%type <student> Student StudentDataList
%type <tipo> StuType
%%

Document	: Students
		|
		;

Students	: Students Student { insertStudent($2); }
	 	| Student { insertStudent($1); }
	 	;

Student		: NUMBER OPEN StudentDataList CLOSE { $$ = insertNumber($1,$3); }
		;

StudentDataList : StudentDataList LABEL_NAME EQUAL STRING STOP { $$ = insertName($1,$4); }
		| StudentDataList LABEL_MEDIA EQUAL NUMBER STOP { $$ = insertAverage($1,$4); }
		| StudentDataList LABEL_TIPO EQUAL StuType STOP { $$ = insertType($1,$4); }
		| StudentDataList LABEL_YEAR EQUAL NUMBER STOP { $$ = insertYear($1,$4); }
		| StudentDataList LABEL_WANTED EQUAL NUMBER STOP { $$ = insertWanted($1,$4); }
		| StudentDataList LABEL_CHOICES OPEN StudentChoices CLOSE { $$ = insertChoices($1,$4); }
		| { $$ = NULL; }
		;

StuType		: LABEL_NORMAL 	{ $$ = NORMAL; }
		| LABEL_PRO	{ $$ = PROFESSIONAL; }
		| LABEL_EXTRA	{ $$ = EXTRA; }
		;


StudentChoices	: StudentChoices STRING EQUAL NUMBER STOP { $$ = insertChoice($1,$2,$4); }
		| { $$ = NULL; }
		; 


%%

static Student * insertType (Student *st, StudentType t) {
        if (!st) st = newStudent();
        st->type = t;
        return st;

}
static Student * insertWanted (Student *st, int t) {
        if (!st) st = newStudent();
        st->ucesWanted = t;
        return st;

}
static Student * insertChoices(Student *st, LinkedList *list) {
        if (!st) st = newStudent();
        st->selections = list;
        return st;
}

static Student * insertNumber(int number, Student *st) {
        if (!st) st = newStudent();
        st->number = number;
        return st;
}

static Student * insertAverage(Student *st, int avg) {
        if (!st) st = newStudent();
        st->average = avg;
        return st;
}

static Student * insertYear(Student *st, int year) {
        if (!st) st = newStudent();
        st->year = year;
        return st;
}

static void insertStudent (Student *st) {
	arrayInsert(result,st);
}
static Student * insertName(Student *st,char *name) {
	if (!st) st = newStudent();
	st->name = name;
	return st;
}
static LinkedList * insertChoice(LinkedList *old, char *uce, int pref) {
	Selection *s = newSelection(uce,pref);
	old = insertElemHead(old,s);
	return old;
}

/*int yywrap () {
	return 1;
}*/

int yyerror (char *err) {
	printf("%s\n",err);
	return 1;
}

ArrayList * readStudents (FILE *fp) {
	studentsin = fp;
	result = newArrayList(STUDENT_LIST_SIZE);
	if (yyparse()) {
		printf("ERRO\n");
		return NULL;
	}
	return result; 
}

void writeStudents (ArrayList *list, FILE *fp) {
	Student *st_aux;
	Selection *s_aux;
	LinkedList *tmp;
	int printChoises = 0;
	int i;
	for (i=0;i<arrayGetLength(list);i++) {
		st_aux = arrayGet(list,i);
		fprintf(fp,"%d {\n",st_aux->number);
		fprintf(fp,"\tNome = '%s';\n",st_aux->name);
		fprintf(fp,"\tAno = %d;\n",st_aux->year);
		fprintf(fp,"\tMedia = %d;\n",st_aux->average);
		fprintf(fp,"\tUces = %d;\n",st_aux->ucesWanted);
		switch (st_aux->type) {
			case NORMAL:
				fprintf(fp,"\tTipo = NORMAL;\n");
				break;
			case PROFESSIONAL:
				fprintf(fp,"\tTipo = PROFISSIONAL;\n");
				break;
			case EXTRA:
				fprintf(fp,"\tTipo = EXTRA;\n");
				break;
		}
		tmp = st_aux->selections;
		if (tmp) {
			fprintf(fp,"\tEscolhas {\n");
			while (tmp) {
				s_aux = getData(tmp);
				fprintf(fp,"\t\t'%s' = %d;\n",s_aux->uceName,s_aux->preference);
				tmp = tmp->next;
			}
			fprintf(fp,"\t}\n");
		}
		fprintf(fp,"}\n");
	}
}
